#ifndef _SQ_PLUS_H_
#define _SQ_PLUS_H_

#include <stdlib.h>
#include <string.h>

#ifdef __APPLE__
#include <malloc/malloc.h>
#else
#ifdef __FreeBSD__
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#endif
#include <memory.h>
#if defined(_MSC_VER) || defined(__BORLANDC__)
#include <tchar.h>
#ifndef UNICODE
#define SCSNPRINTF _snprintf
#define SCPUTS puts
#else
#define SCSNPRINTF _snwprintf
#define SCPUTS _putws
#endif
#else

#define sqT(n) n
#define SCSNPRINTF snprintf
#include <stdio.h>
#define SCPUTS puts
#endif

#if 1
#define SQ_CALL_RAISE_ERROR SQTrue
#else
#define SQ_CALL_RAISE_ERROR SQFalse
#endif


#ifdef _UNICODE
#undef _UNICODE
#include "squirrel.h"
#define _UNICODE
#else
#include "squirrel.h"
#endif
typedef SQInteger BOOL_T;
typedef SQInteger INT_T;
typedef SQFloat   FLOAT_T;
#define TRUE 1
#define FALSE 0

#include "SquirrelObject.h"
#include "SquirrelVM.h"
#include "SquirrelBindingsUtils.h"

namespace SqPlus {

#define SQ_USE_CLASS_INHERITANCE
#define SQ_SUPPORT_INSTANCE_TYPE_INFO
#define SQPLUS_CONST_OPT
#define CPP_STYLE_INHERITANCE

  template<class T> struct TypeWrapper {};
  struct SquirrelNull {};
  struct SQAnything { void * anything; };
  typedef SQAnything * SQAnythingPtr;
  typedef SQChar * SQCharPtr;


  struct ScriptStringVarBase {
    const SQInteger MaxLength;
    SQChar s[1];
    ScriptStringVarBase( SQInteger _MaxLength ) : MaxLength( _MaxLength ) {}
    operator SQChar * () { return &s[0]; }
    operator void * () { return ( void * )&s[0]; }
    const SQChar * operator = ( const SQChar * _s ) {
      return safeStringCopy( s, _s, MaxLength );
    }

    static inline SQChar * safeStringCopy( SQChar * d, const SQChar * s, SQInteger MaxLength ) {
      SQInteger i = 0;
      while( s[i] ) {
        d[i] = s[i];
        i++;
        if( i == MaxLength ) {
          break;
        }
      }
      d[i] = 0;
      return d;
    }
  };


  template<SQInteger MAXLENGTH>
  struct ScriptStringVar : ScriptStringVarBase {
    SQChar ps[MAXLENGTH];
    ScriptStringVar() : ScriptStringVarBase( MAXLENGTH ) {
      s[0] = 0;
    }
    ScriptStringVar( const SQChar * _s ) : ScriptStringVarBase( MAXLENGTH ) {
      *this = _s;
    }
    const SQChar * operator = ( const SQChar * _s ) {
      return safeStringCopy( s, _s, MaxLength );
    }
    const SQChar * operator = ( const ScriptStringVar & _s ) {
      return safeStringCopy( s, _s.s, MaxLength );
    }
    bool operator == ( const ScriptStringVar & _s ) {
      return strcmp( s, _s.s ) == 0;
    }
    bool compareCaseInsensitive( const ScriptStringVar & _s ) {
      return strcasecmp( s, _s.s ) == 0;
    }
  };

  typedef ScriptStringVar<8>   ScriptStringVar8;
  typedef ScriptStringVar<16>  ScriptStringVar16;
  typedef ScriptStringVar<32>  ScriptStringVar32;
  typedef ScriptStringVar<64>  ScriptStringVar64;
  typedef ScriptStringVar<128> ScriptStringVar128;
  typedef ScriptStringVar<256> ScriptStringVar256;


  enum ScriptVarType {VAR_TYPE_NONE = -1, VAR_TYPE_INT = 0, VAR_TYPE_FLOAT, VAR_TYPE_BOOL, VAR_TYPE_CONST_STRING, VAR_TYPE_STRING, VAR_TYPE_USER_POINTER, VAR_TYPE_INSTANCE};

  template <typename T>
  struct TypeInfo {
    const SQChar * typeName;
    enum {TypeID = VAR_TYPE_NONE, Size = 0};
  };


  template<>
  struct TypeInfo<INT_T> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "int" ) ) {}
    enum {TypeID = VAR_TYPE_INT, Size = sizeof( INT_T )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<FLOAT_T> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "float" ) ) {}
    enum {TypeID = VAR_TYPE_FLOAT, Size = sizeof( FLOAT_T )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<bool> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "bool" ) ) {}
    enum {TypeID = VAR_TYPE_BOOL, Size = sizeof( BOOL_T )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<SQUserPointer> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "SQUserPointer" ) ) {}
    enum {TypeID = VAR_TYPE_USER_POINTER, Size = sizeof( SQUserPointer )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<SQAnything> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "SQUserPointer" ) ) {}
    enum {TypeID = VAR_TYPE_USER_POINTER, Size = sizeof( SQUserPointer )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<const SQChar *> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "const SQChar *" ) ) {}
    enum {TypeID = VAR_TYPE_CONST_STRING, Size = sizeof( const SQChar * )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<ScriptStringVarBase> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "ScriptStringVarBase" ) ) {}
    enum {TypeID = VAR_TYPE_STRING, Size = sizeof( ScriptStringVarBase )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };


  template<>
  struct TypeInfo<ScriptStringVar8> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "ScriptStringVar8" ) ) {}
    enum {TypeID = VAR_TYPE_STRING, Size = sizeof( ScriptStringVar8 )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<ScriptStringVar16> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "ScriptStringVar16" ) ) {}
    enum {TypeID = VAR_TYPE_STRING, Size = sizeof( ScriptStringVar16 )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<ScriptStringVar32> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "ScriptStringVar32" ) ) {}
    enum {TypeID = VAR_TYPE_STRING, Size = sizeof( ScriptStringVar32 )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<ScriptStringVar64> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "ScriptStringVar64" ) ) {}
    enum {TypeID = VAR_TYPE_STRING, Size = sizeof( ScriptStringVar64 )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<ScriptStringVar128> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "ScriptStringVar128" ) ) {}
    enum {TypeID = VAR_TYPE_STRING, Size = sizeof( ScriptStringVar128 )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  template<>
  struct TypeInfo<ScriptStringVar256> {
    const SQChar * typeName;
    TypeInfo() : typeName( sqT( "ScriptStringVar256" ) ) {}
    enum {TypeID = VAR_TYPE_STRING, Size = sizeof( ScriptStringVar256 )};
    operator ScriptVarType() { return ScriptVarType( TypeID ); }
  };

  enum VarAccessType {VAR_ACCESS_READ_WRITE = 0, VAR_ACCESS_READ_ONLY = 1 << 0, VAR_ACCESS_CONSTANT = 1 << 1, VAR_ACCESS_STATIC = 1 << 2};

  typedef void ( *CopyVarFunc )( void * dst, void * src );


#define SQ_PLUS_TYPE_TABLE sqT("__SqTypes")

  struct VarRef {
    void * offsetOrAddrOrConst;
    ScriptVarType type;
    SQUserPointer instanceType;
    CopyVarFunc copyFunc;

    SQInteger size;
    short access;
    const SQChar * typeName;
    VarRef() : offsetOrAddrOrConst( 0 ), type( VAR_TYPE_NONE ), instanceType( ( SQUserPointer ) - 1 ), copyFunc( 0 ), size( 0 ), access( VAR_ACCESS_READ_WRITE ) {}
    VarRef( void * _offsetOrAddrOrConst, ScriptVarType _type, SQUserPointer _instanceType, CopyVarFunc _copyFunc, SQInteger _size, VarAccessType _access, const SQChar * _typeName ) :
      offsetOrAddrOrConst( _offsetOrAddrOrConst ), type( _type ), instanceType( _instanceType ), copyFunc( _copyFunc ), size( _size ), access( _access ), typeName( _typeName ) {
      #ifdef SQ_SUPPORT_INSTANCE_TYPE_INFO
      SquirrelObject typeTable = SquirrelVM::GetRootTable().GetValue( SQ_PLUS_TYPE_TABLE );
      if( typeTable.IsNull() ) {
        typeTable = SquirrelVM::CreateTable();
        SquirrelObject root = SquirrelVM::GetRootTable();
        root.SetValue( SQ_PLUS_TYPE_TABLE, typeTable );
      }
      typeTable.SetValue( INT_T( ( size_t )copyFunc ), typeName );
      #endif
    }
  };

  typedef VarRef * VarRefPtr;

  inline void getVarNameTag( SQChar * buff, INT_T maxSize, const SQChar * scriptName ) {
    #if 1
    SQChar * d = buff;
    d[0] = '_';
    d[1] = 'v';
    d = &d[2];
    maxSize -= ( 2 + 1 );
    SQInteger pos = 0;
    while( scriptName[pos] && pos < maxSize ) {
      d[pos] = scriptName[pos];
      pos++;
    }
    d[pos] = 0;
    #else
    SCSNPRINTF( buff, maxSize, sqT( "_v%s" ), scriptName );
    #endif
  }
  SQInteger setVarFunc( HSQUIRRELVM v );
  SQInteger getVarFunc( HSQUIRRELVM v );
  SQInteger setInstanceVarFunc( HSQUIRRELVM v );
  SQInteger getInstanceVarFunc( HSQUIRRELVM v );


  inline void createTableSetGetHandlers( SquirrelObject & so ) {
    SquirrelObject delegate = so.GetDelegate();
    if( !delegate.Exists( sqT( "_set" ) ) ) {
      delegate = SquirrelVM::CreateTable();
      SquirrelVM::CreateFunction( delegate, setVarFunc, sqT( "_set" ), sqT( "sn|b|s" ) );
      SquirrelVM::CreateFunction( delegate, getVarFunc, sqT( "_get" ), sqT( "s" ) );
      so.SetDelegate( delegate );
    }
  }
  inline VarRefPtr createVarRef( SquirrelObject & so, const SQChar * scriptVarName ) {
    VarRefPtr pvr = 0;
    ScriptStringVar256 scriptVarTagName;
    getVarNameTag( scriptVarTagName, sizeof( scriptVarTagName ), scriptVarName );
    if( !so.GetUserData( scriptVarTagName, ( SQUserPointer * )&pvr ) ) {
      so.NewUserData( scriptVarTagName, sizeof( *pvr ) );
      if( !so.GetUserData( scriptVarTagName, ( SQUserPointer * )&pvr ) ) {
        throw SquirrelError( sqT( "Could not create UserData." ) );
      }
    }
    return pvr;
  }
  template<typename T>
  void validateConstantType( T ) {
    switch( TypeInfo<T>() ) {
      case VAR_TYPE_INT:
      case VAR_TYPE_FLOAT:
      case VAR_TYPE_BOOL:
      case VAR_TYPE_CONST_STRING:
        break;
      default:
        throw SquirrelError( sqT( "validateConstantType(): type must be INT, FLOAT, BOOL, or CONST CHAR *." ) );
    }
  }
  inline void createInstanceSetGetHandlers( SquirrelObject & so ) {
    if( !so.Exists( sqT( "_set" ) ) ) {
      SquirrelVM::CreateFunction( so, setInstanceVarFunc, sqT( "_set" ), sqT( "sn|b|s|x" ) );
      SquirrelVM::CreateFunction( so, getInstanceVarFunc, sqT( "_get" ), sqT( "s" ) );
    }
  }

  template<typename T>
  struct ClassType {
    static SQUserPointer type( void ) { return ( SQUserPointer )&copy; }
    static CopyVarFunc getCopyFunc( void ) { return ( CopyVarFunc )&copy; }
    static void copy( T * dst, T * src ) {
      *dst = *src;
    }
  };

  template<typename T>
  void BindVariable( SquirrelObject & so, T * var, const SQChar * scriptVarName, VarAccessType access = VAR_ACCESS_READ_WRITE ) {
    VarRefPtr pvr = createVarRef( so, scriptVarName );
    *pvr = VarRef( var, TypeInfo<T>(), 0, ClassType<T>::getCopyFunc(), sizeof( *var ), access, TypeInfo<T>().typeName );
    createTableSetGetHandlers( so );
  }

  template<typename T>
  void BindConstant( SquirrelObject & so, T constant, const SQChar * scriptVarName ) {
    validateConstantType( constant );
    VarRefPtr pvr = createVarRef( so, scriptVarName );
    #if __cplusplus>=201103L
    static_assert( sizeof( constant ) <= sizeof( void* ), "using larger type" );
    #endif
    void *ptr = reinterpret_cast<void*>( constant );
    *pvr = VarRef( ptr, TypeInfo<T>(), 0, 0, sizeof( constant ), VAR_ACCESS_CONSTANT, TypeInfo<T>().typeName );
    createTableSetGetHandlers( so );
  }
  template<typename T>
  void BindVariable( T * var, const SQChar * scriptVarName, VarAccessType access = VAR_ACCESS_READ_WRITE ) {
    SquirrelObject so = SquirrelVM::GetRootTable();
    BindVariable( so, var, scriptVarName, access );
  }
  template<typename T>
  void BindConstant( T constant, const SQChar * scriptVarName ) {
    SquirrelObject so = SquirrelVM::GetRootTable();
    BindConstant( so, constant, scriptVarName );
  }

  template<typename T>
  void RegisterInstanceVariable( SquirrelObject & so, SQUserPointer classType, T * var, const SQChar * scriptVarName, VarAccessType access = VAR_ACCESS_READ_WRITE ) {
    VarRef * pvr = createVarRef( so, scriptVarName );
    void * offsetOrAddrOrConst = ( void * )var;
    *pvr = VarRef( offsetOrAddrOrConst, TypeInfo<T>(), classType, ClassType<T>::getCopyFunc(), sizeof( *var ), access, TypeInfo<T>().typeName );
    createInstanceSetGetHandlers( so );
  }
  template<typename T>
  void RegisterInstanceConstant( SquirrelObject & so, SQUserPointer classType, T constant, const SQChar * scriptVarName ) {
    validateConstantType( constant );
    VarRef * pvr = createVarRef( so, scriptVarName );
    struct CV {
      T var;
      size_t pad;
    } cv;
    cv.var = constant;
    *pvr = VarRef( *( void ** )&cv, TypeInfo<T>(), classType, 0, sizeof( constant ), VAR_ACCESS_CONSTANT, TypeInfo<T>().typeName );
    createInstanceSetGetHandlers( so );
  }

  inline BOOL_T CreateConstructNativeClassInstance( HSQUIRRELVM v, const SQChar * className ) {
    SQInteger oldtop = sq_gettop( v );
    sq_pushroottable( v );
    sq_pushstring( v, className, -1 );
    if( SQ_FAILED( sq_rawget( v, -2 ) ) ) {
      sq_settop( v, oldtop );
      return FALSE;
    }
    sq_remove( v, -2 );
    sq_pushroottable( v );
    if( SQ_FAILED( sq_call( v, 1, SQTrue, SQ_CALL_RAISE_ERROR ) ) ) {
      sq_settop( v, oldtop );
      return FALSE;
    }
    sq_remove( v, -2 );
    return TRUE;
  }
  template<typename T>
  inline BOOL_T CreateCopyInstance( const SQChar * className, const T & classToCopy ) {
    HSQUIRRELVM v = SquirrelVM::GetVMPtr();
    if( !CreateConstructNativeClassInstance( v, className ) ) {
      return FALSE;
    }
    SQUserPointer up = 0;
    sq_getinstanceup( v, -1, &up, ClassType<T>::type() );
    if( !up ) {
      return FALSE;
    }
    T * newClass = ( T * )up;
    *newClass = classToCopy;
    return TRUE;
  }

  template<typename T>
  inline SquirrelObject NewClassCopy( const SQChar * className, const T & classToCopy ) {
    SquirrelObject ret;
    if( CreateCopyInstance( className, classToCopy ) ) {
      ret.AttachToStackObject( -1 );
      sq_poptop( SquirrelVM::GetVMPtr() );
    } else
    { throw SquirrelError( sqT( "NewClassCopy(): could not create class" ) ); }
    return ret;
  }

  template<typename T>
  inline SQInteger ReturnCopy( HSQUIRRELVM v, const T & classToCopy ) {
    SquirrelObject so( NewClassCopy( GetTypeName( classToCopy ), classToCopy ) );
    return StackHandler( v ).Return( so );
  }

  template<typename T, bool ExceptionOnError>
  T * GetInstance( HSQUIRRELVM v, SQInteger idx ) {
    SQUserPointer up = 0;
    sq_getinstanceup( v, idx, &up, ClassType<T>::type() );
    if( ExceptionOnError ) {
      if( !up ) {
        throw SquirrelError( sqT( "GetInstance: Invalid argument type" ) );
      }
    }
    return ( T * )up;
  }
  #ifdef SQPLUS_SUPPORT_NULL_INSTANCES

#define DECLARE_INSTANCE_TYPE_NAME_T(TYPE,NAME) \
  namespace SqPlus { \
    inline const SQChar * GetTypeName( const TYPE & ) { \
      return sqT( #NAME); \
    } \
    inline void Push( HSQUIRRELVM v, TYPE * value ) { \
      if( !value )  { \
        sq_pushnull( v ); \
      } else if( !CreateNativeClassInstance( v, GetTypeName( *value ), value, 0 ) ) { \
        throw SquirrelError( sqT( "无法创建实例（检查注册名）" ) ); \
      } \
    } \
    inline void Push( HSQUIRRELVM, TYPE & value ) { \
      if( !CreateCopyInstance( GetTypeName( value ), value ) ) { \
        throw SquirrelError( sqT( "无法创建实例副本（检查注册名）" ) ); \
      } \
    } \
    inline bool Match( TypeWrapper<TYPE &>, HSQUIRRELVM v, SQInteger idx ) { \
      return  GetInstance<TYPE, false>( v, idx ) != NULL; \
    } \
    inline bool Match( TypeWrapper<TYPE *>, HSQUIRRELVM v, SQInteger idx ) {  \
      return ( sq_gettype( v, idx ) == OT_NULL ) || ( GetInstance<TYPE, false>( v, idx ) != NULL );  \
    } \
    inline TYPE & Get( TypeWrapper<TYPE &>, HSQUIRRELVM v, SQInteger idx ) {  \
      return *GetInstance<TYPE, true>( v, idx );  \
    } \
    inline TYPE * Get( TypeWrapper<TYPE *>, HSQUIRRELVM v, SQInteger idx ) {  \
      if( sq_gettype( v, idx ) == OT_NULL ) { \
        return NULL; \
      } \
      return GetInstance<TYPE, true>( v, idx ); \
    } \
    template<> \
    struct TypeInfo<TYPE> { \
      const SQChar * typeName; \
      TypeInfo() : typeName( sqT( #NAME)) { \} \
      enum { \
        TypeID = VAR_TYPE_INSTANCE, Size = sizeof( TYPE ) \
      }; \
      operator ScriptVarType() { \
        return ScriptVarType( TypeID ); \
      } \
    }; \
  }

  #else

#define DECLARE_INSTANCE_TYPE_NAME_T(TYPE,NAME)  \
  namespace SqPlus { \
    inline const SQChar * GetTypeName( const TYPE & ) { \
      return sqT( #NAME); } \
    inline void Push( HSQUIRRELVM v, TYPE * value ) { \
      if( !CreateNativeClassInstance( v, GetTypeName( *value ), value, 0 ) ) { \
        throw SquirrelError( sqT( "无法创建实例（检查注册名）" ) ); \
      } \
    } \
    inline void Push( HSQUIRRELVM, TYPE & value ) { \
      if( !CreateCopyInstance( GetTypeName( value ), value ) ) { \
        throw SquirrelError( sqT( "无法创建实例副本（检查注册名）" ) ); \
      } \
    } \
    inline bool Match( TypeWrapper<TYPE &>, HSQUIRRELVM v, SQInteger idx ) { \
      return  GetInstance<TYPE, false>( v, idx ) != NULL; \
    } \
    inline bool Match( TypeWrapper<TYPE *>, HSQUIRRELVM v, SQInteger idx ) { \
      return  GetInstance<TYPE, false>( v, idx ) != NULL; \
    } \
    inline TYPE & Get( TypeWrapper<TYPE &>, HSQUIRRELVM v, SQInteger idx ) { \
      return *GetInstance<TYPE, true>( v, idx ); \
    } \
    inline TYPE * Get( TypeWrapper<TYPE *>, HSQUIRRELVM v, SQInteger idx ) { \
      return  GetInstance<TYPE, true>( v, idx ); \
    } \
    template<> \
    struct TypeInfo<TYPE> { \
      const SQChar * typeName; \
      TypeInfo() : typeName( sqT( #NAME)) {} \
      enum {TypeID = VAR_TYPE_INSTANCE, Size = sizeof( TYPE )}; \
      operator ScriptVarType() { return ScriptVarType( TypeID ); } \
    }; \
  }
  #endif

  #ifndef SQPLUS_CONST_OPT
#define DECLARE_INSTANCE_TYPE(TYPE) DECLARE_INSTANCE_TYPE_NAME_T(TYPE,TYPE)
#define DECLARE_INSTANCE_TYPE_NAME(TYPE,NAME) DECLARE_INSTANCE_TYPE_NAME_T(TYPE,NAME)
  #else
#define SQPLUS_DECLARE_INSTANCE_TYPE_CONST
#include "SqPlusConst.h"
  #endif

  #ifndef SQ_SKIP_ARG_ASSERT
#define sq_argassert(arg,_index_) if (!Match(TypeWrapper<P##arg>(),v,_index_)) return sq_throwerror(v,sqT("Incorrect function argument"))
  #else
#define sq_argassert(arg,_index_)
  #endif


  template<class RT>
  struct ReturnSpecialization {


    static SQInteger Call( RT( *func )(), HSQUIRRELVM v, SQInteger ) {
      RT ret = func();
      Push( v, ret );
      return 1;
    }

    template<typename P1>
    static SQInteger Call( RT( *func )( P1 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      RT ret = func(
                 Get( TypeWrapper<P1>(), v, index + 0 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename P1, typename P2>
    static SQInteger Call( RT( *func )( P1, P2 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      RT ret = func(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename P1, typename P2, typename P3>
    static SQInteger Call( RT( *func )( P1, P2, P3 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      RT ret = func(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename P1, typename P2, typename P3, typename P4>
    static SQInteger Call( RT( *func )( P1, P2, P3, P4 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      RT ret = func(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5>
    static SQInteger Call( RT( *func )( P1, P2, P3, P4, P5 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      RT ret = func(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 ),
                 Get( TypeWrapper<P5>(), v, index + 4 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    static SQInteger Call( RT( *func )( P1, P2, P3, P4, P5, P6 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      RT ret = func(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 ),
                 Get( TypeWrapper<P5>(), v, index + 4 ),
                 Get( TypeWrapper<P6>(), v, index + 5 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    static SQInteger Call( RT( *func )( P1, P2, P3, P4, P5, P6, P7 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      sq_argassert( 7, index + 6 );
      RT ret = func(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 ),
                 Get( TypeWrapper<P5>(), v, index + 4 ),
                 Get( TypeWrapper<P6>(), v, index + 5 ),
                 Get( TypeWrapper<P7>(), v, index + 6 )
               );
      Push( v, ret );
      return 1;
    }


    template <typename Callee>
    static SQInteger Call( Callee & callee, RT( Callee::*func )(), HSQUIRRELVM v, SQInteger ) {
      RT ret = ( callee.*func )();
      Push( v, ret );
      return 1;
    }

    template <typename Callee, typename P1>
    static SQInteger Call( Callee & callee, RT( Callee::*func )( P1 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      RT ret = ( callee.*func )(
                 Get( TypeWrapper<P1>(), v, index + 0 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename Callee, typename P1, typename P2>
    static SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      RT ret = ( callee.*func )(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename Callee, typename P1, typename P2, typename P3>
    static SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      RT ret = ( callee.*func )(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4>
    static SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      RT ret = ( callee.*func )(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4, typename P5>
    static SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4, P5 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      RT ret = ( callee.*func )(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 ),
                 Get( TypeWrapper<P5>(), v, index + 4 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    static SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4, P5, P6 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      RT ret = ( callee.*func )(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 ),
                 Get( TypeWrapper<P5>(), v, index + 4 ),
                 Get( TypeWrapper<P6>(), v, index + 5 )
               );
      Push( v, ret );
      return 1;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    static SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4, P5, P6, P7 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      sq_argassert( 7, index + 6 );
      RT ret = ( callee.*func )(
                 Get( TypeWrapper<P1>(), v, index + 0 ),
                 Get( TypeWrapper<P2>(), v, index + 1 ),
                 Get( TypeWrapper<P3>(), v, index + 2 ),
                 Get( TypeWrapper<P4>(), v, index + 3 ),
                 Get( TypeWrapper<P5>(), v, index + 4 ),
                 Get( TypeWrapper<P6>(), v, index + 5 ),
                 Get( TypeWrapper<P7>(), v, index + 6 )
               );
      Push( v, ret );
      return 1;
    }

#define SQPLUS_CALL_CONST_MFUNC_RET0
#include "SqPlusConst.h"
  };

  template<>
  struct ReturnSpecialization<void> {


    static SQInteger Call( void ( *func )(), HSQUIRRELVM v, SQInteger ) {
      ( void )v;
      func();
      return 0;
    }

    template<typename P1>
    static SQInteger Call( void ( *func )( P1 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      func(
        Get( TypeWrapper<P1>(), v, index + 0 )
      );
      return 0;
    }

    template<typename P1, typename P2>
    static SQInteger Call( void ( *func )( P1, P2 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      func(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 )
      );
      return 0;
    }

    template<typename P1, typename P2, typename P3>
    static SQInteger Call( void ( *func )( P1, P2, P3 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      func(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 )
      );
      return 0;
    }

    template<typename P1, typename P2, typename P3, typename P4>
    static SQInteger Call( void ( *func )( P1, P2, P3, P4 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      func(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 )
      );
      return 0;
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5>
    static SQInteger Call( void ( *func )( P1, P2, P3, P4, P5 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      func(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 ),
        Get( TypeWrapper<P5>(), v, index + 4 )
      );
      return 0;
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    static SQInteger Call( void ( *func )( P1, P2, P3, P4, P5, P6 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      func(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 ),
        Get( TypeWrapper<P5>(), v, index + 4 ),
        Get( TypeWrapper<P6>(), v, index + 5 )
      );
      return 0;
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    static SQInteger Call( void ( *func )( P1, P2, P3, P4, P5, P6, P7 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      sq_argassert( 7, index + 6 );
      func(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 ),
        Get( TypeWrapper<P5>(), v, index + 4 ),
        Get( TypeWrapper<P6>(), v, index + 5 ),
        Get( TypeWrapper<P7>(), v, index + 6 )
      );
      return 0;
    }

    template<typename Callee>
    static SQInteger Call( Callee & callee, void ( Callee::*func )(), HSQUIRRELVM, SQInteger ) {
      ( callee.*func )();
      return 0;
    }

    template<typename Callee, typename P1>
    static SQInteger Call( Callee & callee, void ( Callee::*func )( P1 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      ( callee.*func )(
        Get( TypeWrapper<P1>(), v, index + 0 )
      );
      return 0;
    }

    template<typename Callee, typename P1, typename P2>
    static SQInteger Call( Callee & callee, void ( Callee::*func )( P1, P2 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      ( callee.*func )(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 )
      );
      return 0;
    }

    template<typename Callee, typename P1, typename P2, typename P3>
    static SQInteger Call( Callee & callee, void ( Callee::*func )( P1, P2, P3 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      ( callee.*func )(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 )
      );
      return 0;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4>
    static SQInteger Call( Callee & callee, void ( Callee::*func )( P1, P2, P3, P4 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      ( callee.*func )(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 )
      );
      return 0;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4, typename P5>
    static SQInteger Call( Callee & callee, void ( Callee::*func )( P1, P2, P3, P4, P5 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      ( callee.*func )(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 ),
        Get( TypeWrapper<P5>(), v, index + 4 )
      );
      return 0;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    static SQInteger Call( Callee & callee, void ( Callee::*func )( P1, P2, P3, P4, P5, P6 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      ( callee.*func )(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 ),
        Get( TypeWrapper<P5>(), v, index + 4 ),
        Get( TypeWrapper<P6>(), v, index + 5 )
      );
      return 0;
    }

    template<typename Callee, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    static SQInteger Call( Callee & callee, void ( Callee::*func )( P1, P2, P3, P4, P5, P6, P7 ), HSQUIRRELVM v, SQInteger index ) {
      sq_argassert( 1, index + 0 );
      sq_argassert( 2, index + 1 );
      sq_argassert( 3, index + 2 );
      sq_argassert( 4, index + 3 );
      sq_argassert( 5, index + 4 );
      sq_argassert( 6, index + 5 );
      sq_argassert( 7, index + 6 );
      ( callee.*func )(
        Get( TypeWrapper<P1>(), v, index + 0 ),
        Get( TypeWrapper<P2>(), v, index + 1 ),
        Get( TypeWrapper<P3>(), v, index + 2 ),
        Get( TypeWrapper<P4>(), v, index + 3 ),
        Get( TypeWrapper<P5>(), v, index + 4 ),
        Get( TypeWrapper<P6>(), v, index + 5 ),
        Get( TypeWrapper<P7>(), v, index + 6 )
      );
      return 0;
    }

#define SQPLUS_CALL_CONST_MFUNC_NORET
#include "SqPlusConst.h"

  };

  template<typename RT>
  SQInteger Call( RT( *func )(), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }

  template<typename RT, typename P1>
  SQInteger Call( RT( *func )( P1 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }

  template<typename RT, typename P1, typename P2>
  SQInteger Call( RT( *func )( P1, P2 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }

  template<typename RT, typename P1, typename P2, typename P3>
  SQInteger Call( RT( *func )( P1, P2, P3 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }

  template<typename RT, typename P1, typename P2, typename P3, typename P4>
  SQInteger Call( RT( *func )( P1, P2, P3, P4 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }

  template<typename RT, typename P1, typename P2, typename P3, typename P4, typename P5>
  SQInteger Call( RT( *func )( P1, P2, P3, P4, P5 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }

  template<typename RT, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
  SQInteger Call( RT( *func )( P1, P2, P3, P4, P5, P6 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }

  template<typename RT, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
  SQInteger Call( RT( *func )( P1, P2, P3, P4, P5, P6, P7 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( func, v, index );
  }


  template<typename Callee, typename RT>
  SQInteger Call( Callee & callee, RT( Callee::*func )(), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

  template<typename Callee, typename RT, typename P1>
  SQInteger Call( Callee & callee, RT( Callee::*func )( P1 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

  template<typename Callee, typename RT, typename P1, typename P2>
  SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

  template<typename Callee, typename RT, typename P1, typename P2, typename P3>
  SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

  template<typename Callee, typename RT, typename P1, typename P2, typename P3, typename P4>
  SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

  template<typename Callee, typename RT, typename P1, typename P2, typename P3, typename P4, typename P5>
  SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4, P5 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

  template<typename Callee, typename RT, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
  SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4, P5, P6 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

  template<typename Callee, typename RT, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
  SQInteger Call( Callee & callee, RT( Callee::*func )( P1, P2, P3, P4, P5, P6, P7 ), HSQUIRRELVM v, SQInteger index ) {
    return ReturnSpecialization<RT>::Call( callee, func, v, index );
  }

#define SQPLUS_CALL_CONST_MFUNC_RET1
#include "SqPlusConst.h"

  template<typename Func>
  struct DirectCallFunction {
    static inline SQInteger Dispatch( HSQUIRRELVM v ) {
      StackHandler sa( v );
      SQInteger paramCount = sa.GetParamCount();
      Func * func = ( Func * )sa.GetUserData( paramCount );
      return Call( *func, v, 2 );
    }
  };
  template<typename Callee, typename Func>
  class DirectCallMemberFunction {
    public:
      static inline SQInteger Dispatch( HSQUIRRELVM v ) {
        StackHandler sa( v );
        SQInteger paramCount = sa.GetParamCount();
        unsigned char * ud = ( unsigned char * )sa.GetUserData( paramCount );
        if( !*( Callee** )ud ) {
          return sq_throwerror( v, sqT( "Invalid Instance Type" ) );
        }
        return Call( **( Callee** )ud, *( Func* )( ud + sizeof( Callee* ) ), v, 2 );
      }
  };


#define SQ_CLASS_OBJECT_TABLE_NAME sqT("__ot")
#define SQ_CLASS_HIER_ARRAY sqT("__ca")

  template<typename Callee, typename Func>
  class DirectCallInstanceMemberFunction {
    public:
      static inline SQInteger Dispatch( HSQUIRRELVM v ) {
        StackHandler sa( v );
        Callee * instance = ( Callee * )sa.GetInstanceUp( 1, 0 );
        SQInteger paramCount = sa.GetParamCount();
        Func * func = ( Func * )sa.GetUserData( paramCount );
        if( !instance ) {
          return SQ_OK;
        }
        return Call( *instance, *func, v, 2 );
      }
  };

  template<typename Callee>
  class DirectCallInstanceMemberFunctionVarArgs {
    public:
      typedef SQInteger( Callee::*FuncType )( HSQUIRRELVM );
      static inline SQInteger Dispatch( HSQUIRRELVM v ) {
        StackHandler sa( v );
        Callee * instance = ( Callee * )sa.GetInstanceUp( 1, 0 );
        SQInteger paramCount = sa.GetParamCount();
        FuncType func = *( FuncType * )sa.GetUserData( paramCount );
        sq_poptop( v );
        if( !instance ) {
          return SQ_OK;
        }
        return ( instance->*func )( v );
      }
  };

  template<typename Func>
  inline void sq_pushdirectclosure( HSQUIRRELVM v, Func func, SQUnsignedInteger nupvalues ) {
    SQUserPointer up = sq_newuserdata( v, sizeof( func ) );
    memcpy( up, &func, sizeof( func ) );
    sq_newclosure( v, DirectCallFunction<Func>::Dispatch, nupvalues + 1 );
  }

  template<typename Callee, typename Func>
  inline void sq_pushdirectclosure( HSQUIRRELVM v, const Callee & callee, Func func, SQUnsignedInteger nupvalues ) {
    unsigned char * up = ( unsigned char * )sq_newuserdata( v, sizeof( Callee* ) + sizeof( func ) );
    const SQUserPointer pCallee = ( SQUserPointer )&callee;
    memcpy( up, &pCallee, sizeof( Callee* ) );
    memcpy( up + sizeof( Callee* ), &func, sizeof( func ) );
    sq_newclosure( v, DirectCallMemberFunction<Callee, Func>::Dispatch, nupvalues + 1 );
  }

  template<typename Callee, typename Func>
  inline void sq_pushdirectinstanceclosure( HSQUIRRELVM v, const Callee &, Func func, SQUnsignedInteger nupvalues ) {
    unsigned char * up = ( unsigned char * )sq_newuserdata( v, sizeof( func ) );
    memcpy( up, &func, sizeof( func ) );
    sq_newclosure( v, DirectCallInstanceMemberFunction<Callee, Func>::Dispatch, nupvalues + 1 );
  }

  template<typename Callee>
  inline void sq_pushdirectinstanceclosurevarargs( HSQUIRRELVM v, const Callee & callee, SQInteger( Callee::*func )( HSQUIRRELVM ), SQUnsignedInteger nupvalues ) {
    unsigned char * up = ( unsigned char * )sq_newuserdata( v, sizeof( func ) );
    memcpy( up, &func, sizeof( func ) );
    sq_newclosure( v, DirectCallInstanceMemberFunctionVarArgs<Callee>::Dispatch, nupvalues + 1 );
  }

  template<typename Func>
  inline void Register( HSQUIRRELVM v, Func func, const SQChar * name ) {
    sq_pushstring( v, name, -1 );
    sq_pushdirectclosure( v, func, 0 );
    sq_createslot( v, -3 );
  }

  template<typename Callee, typename Func>
  inline void Register( HSQUIRRELVM v, Callee & callee, Func func, const SQChar * name ) {
    sq_pushstring( v, name, -1 );
    sq_pushdirectclosure( v, callee, func, 0 );
    sq_createslot( v, -3 );
  }

  template<typename Func>
  inline void RegisterGlobal( HSQUIRRELVM v, Func func, const SQChar * name ) {
    sq_pushroottable( v );
    Register( v, func, name );
    sq_poptop( v );
  }
  template<typename Func>
  inline void RegisterGlobal( Func func, const SQChar * name ) {
    RegisterGlobal( SquirrelVM::GetVMPtr(), func, name );
  }

  template<typename Callee, typename Func>
  inline void RegisterGlobal( HSQUIRRELVM v, Callee & callee, Func func, const SQChar * name ) {
    sq_pushroottable( v );
    Register( v, callee, func, name );
    sq_poptop( v );
  }
  template<typename Callee, typename Func>
  inline void RegisterGlobal( Callee & callee, Func func, const SQChar * name ) {
    RegisterGlobal( SquirrelVM::GetVMPtr(), callee, func, name );
  }

  template<typename Func>
  inline void Register( HSQUIRRELVM v, HSQOBJECT hso, Func func, const SQChar * name ) {
    sq_pushobject( v, hso );
    Register( v, func, name );
    sq_poptop( v );
  }
  template<typename Callee, typename Func>
  inline void Register( HSQUIRRELVM v, HSQOBJECT hso, Callee & callee, Func func, const SQChar * name ) {
    sq_pushobject( v, hso );
    Register( v, callee, func, name );
    sq_poptop( v );
  }
  template<typename Callee, typename Func>
  inline void RegisterInstance( HSQUIRRELVM v, HSQOBJECT hclass, Callee & callee, Func func, const SQChar * name ) {
    sq_pushobject( v, hclass );
    sq_pushstring( v, name, -1 );
    sq_pushdirectinstanceclosure( v, callee, func, 0 );
    sq_createslot( v, -3 );
    sq_poptop( v );
  }

  #ifdef _MSC_VER
#pragma warning(disable : 4995)
  #endif
  template<typename Callee>
  inline void RegisterInstanceVarArgs( HSQUIRRELVM v, HSQOBJECT hclass, Callee & callee, SQInteger( Callee::*func )( HSQUIRRELVM ), const SQChar * name, const SQChar * typeMask = sqT( "*" ) ) {
    sq_pushobject( v, hclass );
    sq_pushstring( v, name, -1 );
    sq_pushdirectinstanceclosurevarargs( v, callee, func, 0 );
    SQChar tm[64];
    SQChar * ptm = tm;
    SQInteger numParams = SQ_MATCHTYPEMASKSTRING;
    if( typeMask ) {
      if( typeMask[0] == '*' ) {
        ptm = 0;
      } else {
        if( SCSNPRINTF( tm, sizeof( tm ), sqT( "x%s" ), typeMask ) < 0 ) {
          throw SquirrelError( sqT( "RegisterInstanceVarArgs: typeMask string too long." ) );
        }
      }
    } else {
      tm[0] = 'x';
      tm[1] = 0;
    }
    if( ptm ) {
      sq_setparamscheck( v, numParams, ptm );
    }
    #ifdef _DEBUG
    sq_setnativeclosurename( v, -1, name );
    #endif
    sq_createslot( v, -3 );
    sq_poptop( v );
  }
  #ifdef _MSC_VER
#pragma warning(default : 4995)
  #endif

  template<typename RT>
  struct SquirrelFunction {
    HSQUIRRELVM v;
    SquirrelObject object;
    SquirrelObject func;
    SquirrelFunction() : v( 0 ) {}
    SquirrelFunction( HSQUIRRELVM _v, const SquirrelObject & _object, const SquirrelObject & _func ) : v( _v ), object( _object ), func( _func ) {}
    SquirrelFunction( const SquirrelObject & _object, const SquirrelObject & _func ) : v( SquirrelVM::GetVMPtr() ), object( _object ), func( _func ) {}
    SquirrelFunction( const SquirrelObject & _object, const SQChar * name ) {
      v      = SquirrelVM::GetVMPtr();
      object = _object;
      func   = object.GetValue( name );
    }
    SquirrelFunction( const SQChar * name ) {
      v      = SquirrelVM::GetVMPtr();
      object = SquirrelVM::GetRootTable();
      func   = object.GetValue( name );
    }

    void reset( void ) {
      func.Reset();
      object.Reset();
    }
#define SQPLUS_CHECK_FNCALL(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(sqT("SquirrelFunction<> call failed"))

    RT operator()( void ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      SQPLUS_CHECK_FNCALL( sq_call( v, 1, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

    template<typename P1>
    RT operator()( P1 p1 ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      Push( v, p1 );
      SQPLUS_CHECK_FNCALL( sq_call( v, 2, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

    template<typename P1, typename P2>
    RT operator()( P1 p1, P2 p2 ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      Push( v, p1 );
      Push( v, p2 );
      SQPLUS_CHECK_FNCALL( sq_call( v, 3, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

    template<typename P1, typename P2, typename P3>
    RT operator()( P1 p1, P2 p2, P3 p3 ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      Push( v, p1 );
      Push( v, p2 );
      Push( v, p3 );
      SQPLUS_CHECK_FNCALL( sq_call( v, 4, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

    template<typename P1, typename P2, typename P3, typename P4>
    RT operator()( P1 p1, P2 p2, P3 p3, P4 p4 ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      Push( v, p1 );
      Push( v, p2 );
      Push( v, p3 );
      Push( v, p4 );
      SQPLUS_CHECK_FNCALL( sq_call( v, 5, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5>
    RT operator()( P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      Push( v, p1 );
      Push( v, p2 );
      Push( v, p3 );
      Push( v, p4 );
      Push( v, p5 );
      SQPLUS_CHECK_FNCALL( sq_call( v, 6, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
    RT operator()( P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6 ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      Push( v, p1 );
      Push( v, p2 );
      Push( v, p3 );
      Push( v, p4 );
      Push( v, p5 );
      Push( v, p6 );
      SQPLUS_CHECK_FNCALL( sq_call( v, 7, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

    template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
    RT operator()( P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7 ) {
      sq_pushobject( v, func.GetObjectHandle() );
      sq_pushobject( v, object.GetObjectHandle() );
      Push( v, p1 );
      Push( v, p2 );
      Push( v, p3 );
      Push( v, p4 );
      Push( v, p5 );
      Push( v, p6 );
      Push( v, p7 );
      SQPLUS_CHECK_FNCALL( sq_call( v, 8, SQTrue, SQ_CALL_RAISE_ERROR ) );
      return GetRet( TypeWrapper<RT>(), v, -1 );
    }

  };


#define SQ_DELETE_CLASS(CLASSTYPE) if (up) { CLASSTYPE * self = (CLASSTYPE *)up; delete self;} return 0
#define SQ_DECLARE_RELEASE(CLASSTYPE) \
  static SQInteger release(SQUserPointer up, SQInteger ) { \
    SQ_DELETE_CLASS(CLASSTYPE); \
  }

  template<typename T>
  struct ReleaseClassPtrPtr {
    static SQInteger release( SQUserPointer up, SQInteger size ) {
      if( up ) {
        T ** self = ( T ** )up;
        delete *self;
      }
      return 0;
    }
  };

  template<typename T>
  struct ReleaseClassPtr {
    static SQInteger release( SQUserPointer up, SQInteger size ) {
      if( up ) {
        T * self = ( T * )up;
        delete self;
      }
      return 0;
    }
  };

  BOOL_T CreateClass( HSQUIRRELVM v, SquirrelObject & newClass, SQUserPointer classType, const SQChar * name, const SQChar * baseName = 0 );

#define SQ_ANCESTOR_CLASS_INDEX sqT("__ci")

  template<typename T>
  inline SQInteger PostConstruct( HSQUIRRELVM v, T * newClass, SQRELEASEHOOK hook ) {
    #ifdef SQ_USE_CLASS_INHERITANCE
    StackHandler sa( v );
    HSQOBJECT ho = sa.GetObjectHandle( 1 );
    SquirrelObject instance( ho );
    INT_T classIndex = instance.GetValue( SQ_ANCESTOR_CLASS_INDEX ).ToInteger();
    if( classIndex == -1 ) {
      SquirrelObject newObjectTable = SquirrelVM::CreateTable();
      newObjectTable.SetUserPointer( INT_T( ( size_t )ClassType<T>::type() ), newClass );
      instance.SetValue( SQ_CLASS_OBJECT_TABLE_NAME, newObjectTable );
      SquirrelObject classHierArray = instance.GetValue( SQ_CLASS_HIER_ARRAY );
      INT_T count = classHierArray.Len();
      if( count > 1 ) {
        --count;
        for( INT_T i = 0; i < count; i++ ) {
          #ifdef CPP_STYLE_INHERITANCE
          SquirrelObject so = classHierArray.GetValue( i );
          sq_pushobject( v, so.GetObjectHandle() );
          SQUserPointer typeTag;
          sq_gettypetag( v, -1, &typeTag );
          newObjectTable.SetUserPointer( INT_T( size_t( typeTag ) ), newClass );
          sq_poptop( v );
          #else
          instance.SetValue( SQ_ANCESTOR_CLASS_INDEX, i );
          INT_T top = sq_gettop( v );
          SquirrelObject so = classHierArray.GetValue( i );
          SquirrelObject func = so.GetValue( sqT( "constructor" ) );
          sq_pushobject( v, func.GetObjectHandle() );
          sq_pushobject( v, instance.GetObjectHandle() );
          sq_call( v, 1, SQFalse, SQ_CALL_RAISE_ERROR );
          sq_settop( v, top );
          #endif
        }
        instance.SetValue( SQ_ANCESTOR_CLASS_INDEX, SquirrelObject() );
      }
    } else {
      SquirrelObject objectTable = instance.GetValue( SQ_CLASS_OBJECT_TABLE_NAME );
      objectTable.SetUserPointer( INT_T( ( size_t )ClassType<T>::type() ), newClass );
      INT_T top = sq_gettop( v );
      T ** ud = ( T ** )sq_newuserdata( v, sizeof( T * ) );
      *ud = newClass;
      SquirrelObject userData;
      userData.AttachToStackObject( -1 );
      SquirrelObject classHierArray = instance.GetValue( SQ_CLASS_HIER_ARRAY );
      classHierArray.SetValue( classIndex, userData );
      sq_settop( v, top );
      return TRUE;
    }
    #endif
    sq_setinstanceup( v, 1, newClass );
    sq_setreleasehook( v, 1, hook );
    return 1;
  }
  template<typename T>
  struct ConstructReleaseClass {
    static SQInteger construct( HSQUIRRELVM v ) {
      return PostConstruct<T>( v, new T(), release );
    }
    static SQInteger no_construct( HSQUIRRELVM v ) {
      return PostConstruct<T>( v, 0, 0 );
    }
    SQ_DECLARE_RELEASE( T )
  };

  template<typename T>
  inline SquirrelObject RegisterClassType( HSQUIRRELVM v, const SQChar * scriptClassName, const SQChar * baseScriptClassName = 0 ) {
    SQInteger top = sq_gettop( v );
    SquirrelObject newClass;
    if( CreateClass( v, newClass, ( SQUserPointer )ClassType<T>::type(), scriptClassName, baseScriptClassName ) ) {
      SquirrelVM::CreateFunction( newClass, &ConstructReleaseClass<T>::no_construct, sqT( "constructor" ) );
      #ifdef SQ_USE_CLASS_INHERITANCE
      if( !newClass.Exists( SQ_CLASS_OBJECT_TABLE_NAME ) ) {
        SquirrelObject objectTable = SquirrelVM::CreateTable();
        newClass.SetValue( SQ_CLASS_OBJECT_TABLE_NAME, objectTable );
      }
      SquirrelObject classHierArray;
      if( !newClass.Exists( SQ_CLASS_HIER_ARRAY ) ) {
        classHierArray = SquirrelVM::CreateArray( 0 );
        newClass.SetValue( SQ_CLASS_HIER_ARRAY, classHierArray );
      } else
      { classHierArray = newClass.GetValue( SQ_CLASS_HIER_ARRAY ); }
      classHierArray.ArrayAppend( newClass );
      newClass.SetValue( SQ_ANCESTOR_CLASS_INDEX, ( SQInteger ) - 1 );
      #endif
    }
    sq_settop( v, top );
    return newClass;
  }
  template<typename TClassType>
  struct SQClassDef {
    HSQUIRRELVM v;
    const SQChar * name;
    const SQChar * base;
    SquirrelObject newClass;

    #ifdef SQ_USE_CLASS_INHERITANCE
    SQClassDef( HSQUIRRELVM _v, const SQChar * _name, const SQChar * _base = 0 ) : v( _v ), name( _name ), base( _base ) {
      newClass = RegisterClassType<TClassType>( v, name, base );
    }
    SQClassDef( const SQChar * _name, const SQChar * _base = 0 ) : name( _name ), base( _base ) {
      v = SquirrelVM::GetVMPtr();
      newClass = RegisterClassType<TClassType>( v, name, base );
    }
    #else
    SQClassDef( HSQUIRRELVM _v, const SQChar * _name ) : v( _v ), name( _name ) {
      newClass = RegisterClassType<TClassType>( v, name );
    }

    SQClassDef( const SQChar * _name ) : name( _name ) {
      v = SquirrelVM::GetVMPtr();
      newClass = RegisterClassType<TClassType>( v, name );
    }
    #endif

    SQClassDef & emptyCtor() {
      SquirrelVM::CreateFunction( newClass, &ConstructReleaseClass<TClassType>::construct, sqT( "constructor" ) );
      return *this;
    }
    template<typename Func>
    SQClassDef & func( Func pfunc, const SQChar * name_ ) {
      RegisterInstance( v, newClass.GetObjectHandle(), *( TClassType * )0, pfunc, name_ );
      return *this;
    }
    template<typename Func>
    SQClassDef & funcVarArgs( Func pfunc, const SQChar * name_, const SQChar * typeMask = sqT( "*" ) ) {
      RegisterInstanceVarArgs( v, newClass.GetObjectHandle(), *( TClassType * )0, pfunc, name_, typeMask );
      return *this;
    }
    template<typename Func>
    SQClassDef & staticFuncVarArgs( Func pfunc, const SQChar * name_, const SQChar * typeMask = sqT( "*" ) ) {
      SquirrelVM::PushObject( newClass );
      SquirrelVM::CreateFunction( pfunc, name_, typeMask );
      SquirrelVM::Pop( 1 );
      return *this;
    }
    template<typename Func>
    SQClassDef & staticFunc( Func pfunc, const SQChar * name_ ) {
      Register( v, newClass.GetObjectHandle(), pfunc, name_ );
      return *this;
    }
    template<typename Callee, typename Func>
    SQClassDef & staticFunc( Callee & callee, Func pfunc, const SQChar * name_ ) {
      Register( v, newClass.GetObjectHandle(), callee, pfunc, name_ );
      return *this;
    }

    template<typename VarType>
    SQClassDef & var( VarType TClassType::* pvar, const SQChar * name_, VarAccessType access = VAR_ACCESS_READ_WRITE ) {
      struct CV {
        VarType TClassType::* var;
      } cv;
      cv.var = pvar;
      RegisterInstanceVariable( newClass, ClassType<TClassType>::type(), *( VarType ** )&cv, name_, access );
      return *this;
    }
    template<typename VarType>
    SQClassDef & varAsUserPointer( VarType TClassType::* pvar, const SQChar * name_ ) {
      struct CV {
        VarType TClassType::* var;
      } cv;
      cv.var = pvar;
      RegisterInstanceVariable( newClass, ClassType<TClassType>::type(), *( SQAnything ** )&cv, name_, VAR_ACCESS_READ_ONLY );
      return *this;
    }
    template<typename VarType>
    SQClassDef & staticVar( VarType * pvar, const SQChar * name_, VarAccessType access = VAR_ACCESS_READ_WRITE ) {
      struct CV {
        VarType * var;
      } cv;
      cv.var = pvar;
      RegisterInstanceVariable( newClass, ClassType<TClassType>::type(), *( VarType ** )&cv, name_, VarAccessType( access | VAR_ACCESS_STATIC ) );
      return *this;
    }
#define SQ_REG_CONST_STATIC_VAR
#include "SqPlusConst.h"

    template<typename ConstantType>
    SQClassDef & constant( ConstantType constant_, const SQChar * name_ ) {
      RegisterInstanceConstant( newClass, ClassType<TClassType>::type(), constant_, name_ );
      return *this;
    }
    SQClassDef & enumInt( SQInteger constant_, const SQChar * name_ ) {
      RegisterInstanceConstant( newClass, ClassType<TClassType>::type(), constant_, name_ );
      return *this;
    }
  };

  inline void Push( HSQUIRRELVM v, char value )               { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, unsigned char value )      { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, short value )              { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, unsigned short value )     { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, int value )                { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, unsigned int value )       { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, long value )               { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, long long value )          { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, unsigned long value )      { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, unsigned long long value ) { sq_pushinteger( v, value ); }
  inline void Push( HSQUIRRELVM v, double value )             { sq_pushfloat( v, ( FLOAT_T )value ); }
  inline void Push( HSQUIRRELVM v, float value )              { sq_pushfloat( v, ( FLOAT_T )value ); }
  inline void Push( HSQUIRRELVM v, const SQChar * value )     { sq_pushstring( v, value, -1 ); }
  inline void Push( HSQUIRRELVM v, const SquirrelNull & )     { sq_pushnull( v ); }
  inline void Push( HSQUIRRELVM v, SQFUNCTION value )         { sq_pushuserpointer( v, ( void* )value ); }
  inline void Push( HSQUIRRELVM v, SQAnythingPtr value )      { sq_pushuserpointer( v, ( void* )value ); }
  inline void Push( HSQUIRRELVM v, SquirrelObject & so )      { sq_pushobject( v, so.GetObjectHandle() ); }


#define USE_ARGUMENT_DEPENDANT_OVERLOADS
  #ifdef USE_ARGUMENT_DEPENDANT_OVERLOADS
  #ifdef _MSC_VER
#pragma warning (disable:4675)
  #endif
  inline void Push( HSQUIRRELVM v, bool value )                  { sq_pushbool( v, value ); }
  inline void Push( HSQUIRRELVM v, const void * value )          { sq_pushuserpointer( v, ( void* )value ); }
  inline void Push( HSQUIRRELVM v, const SQUserPointer & value ) { sq_pushuserpointer( v, ( void* )value ); }
  #endif

#define SQPLUS_CHECK_GET(res) if (!SQ_SUCCEEDED(res)) throw SquirrelError(sqT("sq_get*() failed (type error)"))

  inline bool Match( TypeWrapper<bool>, HSQUIRRELVM v, SQInteger idx )               { return sq_gettype( v, idx ) == OT_BOOL; }
  inline bool Match( TypeWrapper<char>, HSQUIRRELVM v, SQInteger idx )               { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<unsigned char>, HSQUIRRELVM v, SQInteger idx )     { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<short>, HSQUIRRELVM v, SQInteger idx )              { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<unsigned short>, HSQUIRRELVM v, SQInteger idx )     { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<int>, HSQUIRRELVM v, SQInteger idx )                { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<unsigned int>, HSQUIRRELVM v, SQInteger idx )       { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<long>, HSQUIRRELVM v, SQInteger idx )               { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<long long>, HSQUIRRELVM v, SQInteger idx )          { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<unsigned long>, HSQUIRRELVM v, SQInteger idx )      { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<unsigned long long>, HSQUIRRELVM v, SQInteger idx ) { return sq_gettype( v, idx ) == OT_INTEGER; }
  inline bool Match( TypeWrapper<float>, HSQUIRRELVM v, SQInteger idx )              { SQInteger type = sq_gettype( v, idx ); return type == OT_FLOAT; }
  inline bool Match( TypeWrapper<double>, HSQUIRRELVM v, SQInteger idx )             { SQInteger type = sq_gettype( v, idx ); return type == OT_FLOAT; }
  inline bool Match( TypeWrapper<const SQChar *>, HSQUIRRELVM v, SQInteger idx )     { return sq_gettype( v, idx ) == OT_STRING; }
  inline bool Match( TypeWrapper<HSQUIRRELVM>, HSQUIRRELVM, SQInteger ) { return true; }
  inline bool Match( TypeWrapper<void*>, HSQUIRRELVM v, SQInteger idx )              { return sq_gettype( v, idx ) == OT_USERPOINTER; }
  inline bool Match( TypeWrapper<SquirrelObject>, HSQUIRRELVM, SQInteger ) { return true; }
  inline void               Get( TypeWrapper<void>, HSQUIRRELVM, int )                      { ; }
  inline bool               Get( TypeWrapper<bool>, HSQUIRRELVM v, SQInteger idx )                { SQBool b; SQPLUS_CHECK_GET( sq_getbool( v, idx, &b ) ); return b != 0; }
  inline char               Get( TypeWrapper<char>, HSQUIRRELVM v, SQInteger idx )                { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<char>( i ); }
  inline unsigned char      Get( TypeWrapper<unsigned char>, HSQUIRRELVM v, SQInteger idx )       { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<unsigned char>( i ); }
  inline short              Get( TypeWrapper<short>, HSQUIRRELVM v, SQInteger idx )               { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<short>( i ); }
  inline unsigned short     Get( TypeWrapper<unsigned short>, HSQUIRRELVM v, SQInteger idx )      { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<unsigned short>( i ); }
  inline int                Get( TypeWrapper<int>, HSQUIRRELVM v, SQInteger idx )                 { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return i; }
  inline unsigned int       Get( TypeWrapper<unsigned int>, HSQUIRRELVM v, SQInteger idx )        { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<unsigned int>( i ); }
  inline long               Get( TypeWrapper<long>, HSQUIRRELVM v, SQInteger idx )                { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<long>( i ); }
  inline long long          Get( TypeWrapper<long long>, HSQUIRRELVM v, SQInteger idx )           { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<long long>( i ); }
  inline unsigned long      Get( TypeWrapper<unsigned long>, HSQUIRRELVM v, SQInteger idx )       { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<unsigned long>( i ); }
  inline unsigned long long Get( TypeWrapper<unsigned long long>, HSQUIRRELVM v, SQInteger idx ) { INT_T i; SQPLUS_CHECK_GET( sq_getinteger( v, idx, &i ) ); return static_cast<unsigned long long>( i ); }
  inline float              Get( TypeWrapper<float>, HSQUIRRELVM v, SQInteger idx )               { FLOAT_T f; SQPLUS_CHECK_GET( sq_getfloat( v, idx, &f ) ); return f; }
  inline double             Get( TypeWrapper<double>, HSQUIRRELVM v, SQInteger idx )              { FLOAT_T f; SQPLUS_CHECK_GET( sq_getfloat( v, idx, &f ) ); return static_cast<double>( f ); }
  inline const SQChar *     Get( TypeWrapper<const SQChar *>, HSQUIRRELVM v, SQInteger idx )      { const SQChar * s; SQPLUS_CHECK_GET( sq_getstring( v, idx, &s ) ); return s; }
  inline SquirrelNull       Get( TypeWrapper<SquirrelNull>, HSQUIRRELVM v, SQInteger idx )        { ( void )v, ( void )idx; return SquirrelNull();  }
  inline void *             Get( TypeWrapper<void *>, HSQUIRRELVM v, SQInteger idx )              { SQUserPointer p; SQPLUS_CHECK_GET( sq_getuserpointer( v, idx, &p ) ); return p; }
  inline HSQUIRRELVM        Get( TypeWrapper<HSQUIRRELVM>, HSQUIRRELVM v, SQInteger )     { sq_poptop( v ); return v; }
  inline SquirrelObject     Get( TypeWrapper<SquirrelObject>, HSQUIRRELVM v, SQInteger idx )      { HSQOBJECT o; SQPLUS_CHECK_GET( sq_getstackobj( v, idx, &o ) ); return SquirrelObject( o ); }

  #ifdef SQPLUS_SUPPORT_STD_STRING
  inline void Push( HSQUIRRELVM v, const std::string& value ) { sq_pushstring( v, value.c_str(), -1 ); }
  inline bool Match( TypeWrapper<const std::string&>, HSQUIRRELVM v, SQInteger idx ) { return sq_gettype( v, idx ) == OT_STRING; }
  inline std::string Get( TypeWrapper<const std::string&>, HSQUIRRELVM v, SQInteger idx ) { const SQChar * s; SQPLUS_CHECK_GET( sq_getstring( v, idx, &s ) ); return std::string( s ); }
  #endif

  #ifdef SQPLUS_SUPPORT_SQ_STD_STRING
  typedef std::basic_string<SQChar> sq_std_string;
  inline void Push( HSQUIRRELVM v, const sq_std_string & value ) { sq_pushstring( v, value.c_str(), -1 ); }
  inline bool Match( TypeWrapper<const sq_std_string &>, HSQUIRRELVM v, SQInteger idx ) { return sq_gettype( v, idx ) == OT_STRING; }
  inline sq_std_string Get( TypeWrapper<const sq_std_string &>, HSQUIRRELVM v, SQInteger idx ) { const SQChar * s; SQPLUS_CHECK_GET( sq_getstring( v, idx, &s ) ); return sq_std_string( s ); }
  #endif

  template<typename RT>
  inline RT GetRet( TypeWrapper<RT>, HSQUIRRELVM v, SQInteger idx ) { RT ret = Get( TypeWrapper<RT>(), v, idx ); sq_pop( v, 2 ); return ret; }
  inline void GetRet( TypeWrapper<void>, HSQUIRRELVM v, SQInteger ) { sq_pop( v, 2 ); }

#define SQ_DECLARE_CLASS(CLASSNAME)                                  \
  static SQInteger _##CLASSNAME##_release(SQUserPointer up,SQInteger size) { \
    if (up) {                                                          \
      CLASSNAME * self = (CLASSNAME *)up;                              \
      delete self;                                                     \
    }                                                                  \
    return 0;                                                          \
  }                                                                    \
  static SQInteger _##CLASSNAME##_constructor(HSQUIRRELVM v) {               \
    CLASSNAME * pc = new CLASSNAME();                                  \
    sq_setinstanceup(v,1,pc);                                          \
    sq_setreleasehook(v,1,_##CLASSNAME##_release);                     \
    return 1;                                                          \
  }

#define SQ_REGISTER_CLASS(CLASSNAME)                                 \
  RegisterClassType(SquirrelVM::GetVMPtr(),sqT(#CLASSNAME),_##CLASSNAME##_constructor)

#define SQ_REGISTER_INSTANCE(NEWSQCLASS,CCLASS,FUNCNAME)             \
  RegisterInstance(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,sqT(#FUNCNAME));

#define SQ_REGISTER_INSTANCE_VARARGS(NEWSQCLASS,CCLASS,FUNCNAME)     \
  RegisterInstanceVarArgs(SquirrelVM::GetVMPtr(),NEWSQCLASS.GetObjectHandle(),*(CCLASS *)0,&CCLASS::FUNCNAME,sqT(#FUNCNAME));

#define SQ_REGISTER_INSTANCE_VARIABLE(NEWSQCLASS,CCLASS,VARNAME)     \
  RegisterInstanceVariable(NEWSQCLASS,&((CCLASS *)0)->VARNAME,sqT(#VARNAME));

  #if defined(USE_ARGUMENT_DEPENDANT_OVERLOADS) && defined(_MSC_VER)
#pragma warning (default:4675)
  #endif

};
#endif
